// 所有权的规则。

// 1、Rust 中的每一个值都有一个被称为其 所有者（owner）的变量。
// 2、值有且只有一个所有者。
// 3、当所有者（变量）离开作用域，这个值将被丢弃。

fn user() {
    let s1 = String::from("hello");
    // 这些 & 符号就是 引用，它们允许你使用值但不获取其所有权
    let len = calculate_length(&s1);
    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}
// Rust 采取了一个不同的策略：内存在拥有它的变量离开作用域后就被自动释放。

fn scope() {
    {
        let s = String::from("hello"); // 从此处起，s 是有效的
        // 使用 s
    } // 此作用域已结束，
    // s 不再有效
}

fn shallow() {
    let x = 5;
    let y = x;
    //与其尝试拷贝被分配的内存，Rust 则认为 s1 不再有效 移动（move）
    let s1 = String::from("hello");
    let s2 = s1;

    // 确实 需要深度复制 String 中堆上的数据，
    // 而不仅仅是栈上的数据，可以使用一个叫做 clone 的通用函数

    let s1 = String::from("hello");
    let s2 = s1.clone();
    println!("s1 = {}, s2 = {}", s1, s2);
}

fn main() {
    let s = String::from("hello"); // s 进入作用域
    takes_ownership(s); // s 的值移动到函数里 ...
    // ... 所以到这里不再有效
    let x = 5; // x 进入作用域
    makes_copy(x); // x 应该移动函数里，
    // 但 i32 是 Copy 的，所以在后面可继续使用 x
}

// 这里, x 先移出了作用域，然后是 s。但因为 s 的值已被移走，
// 所以不会有特殊操作
fn takes_ownership(some_string: String) {
    // some_string 进入作用域
    println!("{}", some_string);
}

// 这里，some_string 移出作用域并调用 `drop` 方法。占用的内存被释放
fn makes_copy(some_integer: i32) {
    // some_integer 进入作用域
    println!("{}", some_integer);
} // 这里，some_integer 移出作用域。不会有特殊操作

fn mai3n() {
    let s1 = gives_ownership(); // gives_ownership 将返回值
    // 移给 s1
    let s2 = String::from("hello"); // s2 进入作用域
    let s3 = takes_and_gives_back(s2); // s2 被移动到
    // takes_and_gives_back 中,
    // 它也将返回值移给 s3
}

// 这里, s3 移出作用域并被丢弃。s2 也移出作用域，但已被移走，
// 所以什么也不会发生。s1 移出作用域并被丢弃
fn gives_ownership() -> String {
    // gives_ownership 将返回值移动给
    // 调用它的函数
    let some_string = String::from("hello"); // some_string 进入作用域.
    some_string // 返回 some_string 并移出给调用的函数
}

// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(a_string: String) -> String {
    // a_string 进入作用域
    a_string // 返回 a_string 并移出给调用的函数
}

//如果我们想要函数使用一个值但不获取所有权该怎么办呢 -->引用

fn main3() {
    let s1 = String::from("hello");
    let (s2, len) = calculate_length3(s1);
    println!("The length of '{}' is {}.", s2, len);
}

fn calculate_length3(s: String) -> (String, usize) {
    let length = s.len(); // len() 返回字符串的长度
    (s, length)
}
